import 'package:flutter/material.dart';

import '../model/grid_calc_result.dart';

class AutoGrid extends StatelessWidget {
  final int Function(BoxConstraints constraints)? getExpectRowCount;
  final double expectItemWidth;
  final double expectItemHeight;
  final double? mainAxisSpacing;
  final double? crossAxisSpacing;
  final bool? paging;
  final List<Widget> children;
  final bool? keepProportion;
  final double Function(double itemWidth)? calcHeight;

  const AutoGrid({
    super.key,
    required this.expectItemWidth,
    required this.expectItemHeight,
    required this.children,
    this.mainAxisSpacing,
    this.crossAxisSpacing,
    this.paging,
    this.keepProportion,
    this.calcHeight,
    this.getExpectRowCount,
  });

  CalcResult calcCount(
      {required BoxConstraints constraints,
      required double wrapSize,
      required double itemSize,
      double? spacing}) {
    spacing = spacing ?? 0;
    int count = 1;
    while (true) {
      if (count * itemSize + (count - 1) * spacing > wrapSize) {
        break;
      }
      count++;
    }
    count -= 1;
    if (getExpectRowCount != null) {
      int expectRowCount = getExpectRowCount!(constraints);
      if (expectRowCount < count) {
        count = expectRowCount;
      }
    }
    double newSize = (wrapSize - (count - 1) * spacing) / count;
    return CalcResult(count, newSize);
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (context, constraints) {
      CalcResult crossAxisCalcRes = calcCount(
          constraints: constraints,
          wrapSize: constraints.maxWidth,
          itemSize: expectItemWidth,
          spacing: crossAxisSpacing);
      double itemHeight;
      if (calcHeight != null) {
        itemHeight = calcHeight!(crossAxisCalcRes.itemSize);
      } else if (keepProportion == true) {
        itemHeight =
            crossAxisCalcRes.itemSize * expectItemHeight / expectItemWidth;
      } else {
        itemHeight = calcCount(
                constraints: constraints,
                wrapSize: constraints.maxHeight,
                itemSize: expectItemHeight,
                spacing: mainAxisSpacing)
            .itemSize;
      }

      return GridView.count(
          padding: EdgeInsets.zero,
          crossAxisCount: crossAxisCalcRes.directionCount,
          childAspectRatio: crossAxisCalcRes.itemSize / itemHeight,
          mainAxisSpacing: mainAxisSpacing ?? 0,
          crossAxisSpacing: crossAxisSpacing ?? 0,
          children: children);
    });
  }
}
